/*
* DxDiag Implementation
*
* Copyright 2009 Austin English
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "resources.h"
#include "globals.h"
#include "dxdiagcom.h"
#include "main_dialog.h"
#include "displaydialog.h"
#include "directxfiles_tab.h"
#include "sound_tab.h"
#include "system_tab.h"
#include "utility.h"
#include "cmdline.h"
#include "input_tab.h"
#include <assert.h>
#include <windows.h>
#include <commctrl.h>
#include <windows.h>
#include <shellapi.h>
#include <ctype.h>
#include <stdio.h>
#include <wchar.h>
#include <dxdiag.h>
#ifdef __WINE__
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dxdiag);
#else
#endif

/* Standalone */
static WCHAR g_mainClassName[] = { 'W', 'I', 'N', 'D', 'O', 'W', 0 };

/* Procedure for our window, controls behavior */
LRESULT CALLBACK main_wnd_proc(HWND, UINT, WPARAM, LPARAM);

#ifdef __WINE__
#define WINMAIN_ENTRY wWinMain
#else
#define WINMAIN_ENTRY WinMain
#endif
int WINAPI WINMAIN_ENTRY(HINSTANCE hInst, HINSTANCE hPrevInst,
                         LPSTR cmdline, int cmdshow)
{
    MSG msg;
    WNDCLASSEXW mainWindow;
    WCHAR *title;
    WCHAR *wcmdline = GetCommandLineW();
    IDxDiagContainer *dxRoot = NULL;

    /* Initialize globals */
    initialize_globals();

    /* Get global module handle */
    g_hinstance = GetModuleHandleW(0);

    /* Initialize DxDiagCOM container */
    if (FAILED(DxDiagCOM_init(&dxRoot)))
        return 1;

    if (!DxDiagCOM_ParseRoot(dxRoot, &g_dxdiagcom_root))
        return 1;

    /* Process the command line */
    if (ProcessCommandLine(wcmdline))
        return 0;

    /* Create main window and register */
    mainWindow.cbSize = sizeof(WNDCLASSEXW);
    mainWindow.style = 0;       /* Window class style */
    mainWindow.lpfnWndProc = main_wnd_proc;     /* Points to WndProc */
    mainWindow.cbClsExtra = 0;  /* Extra memory not needed */
    mainWindow.cbWndExtra = 0;
    mainWindow.hInstance = hInst;
    mainWindow.hIcon = LoadIconW(NULL, MAKEINTRESOURCEW(IDI_APPLICATION));
    mainWindow.hCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_ARROW));
    mainWindow.hbrBackground = (HBRUSH) (COLOR_WINDOWFRAME);
    mainWindow.lpszClassName = g_mainClassName;
    mainWindow.hIconSm =
        LoadIconW(NULL, MAKEINTRESOURCEW(IDI_APPLICATION));
    mainWindow.lpszMenuName = 0;
    if (!RegisterClassExW(&mainWindow)) {
        messageboxw_resource(NULL, STRING_ERROR_MAIN_WINDOW_REGISTRATION,
                             STRING_COMMON_ERROR,
                             MB_ICONEXCLAMATION | MB_OK);
        return 1;
    }

    /* Creates the actual window */
    LoadStringW(hInst, STRING_WINDOW_TITLE, (WCHAR*)&title, 0);
    g_hwndmain = CreateWindowExW(WS_EX_CLIENTEDGE, g_mainClassName, title, WS_OVERLAPPEDWINDOW  /*&(~WS_THICKFRAME) */
                                 , CW_USEDEFAULT, CW_USEDEFAULT,
                                 CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,
                                 hInst, NULL);
    if (g_hwndmain == NULL) {
        messageboxw_resource(NULL, STRING_ERROR_MAIN_WINDOW_CREATION,
                             STRING_COMMON_ERROR,
                             MB_ICONEXCLAMATION | MB_OK);
        return 1;
    }

    /* Show window, enter event loop */
    ShowWindow(g_hwndmain, SW_SHOW);
    UpdateWindow(g_hwndmain);
    while (GetMessageW(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }

    return msg.wParam;
}

VOID create_dialogs(HWND hwnd)
{
    int i, tabIndex = 0, totalTabs;
    Tab *tabs;

#ifdef TEST_MULTIPLE_SOUND
    g_dxdiagcom_root.numSoundDevices = 3;
#endif

    /* Allocate the correct number of tabs and create the TabControl */
    totalTabs = TAB_COUNT - 2 + g_dxdiagcom_root.numSoundDevices
        + g_dxdiagcom_root.numDisplayDevices;
    tabs = calloc(totalTabs, sizeof(Tab));
    tab_control_initialize(&g_tabcontrol, tabs, totalTabs);

    /* Create the dialogs in order */
    create_main_dialog(hwnd);
    createSystemTabDialog(&tabs[TAB_SYSTEM]);
    create_directxfiles_tab(&tabs[TAB_DIRECTX]);
    for (i = 0; i < g_dxdiagcom_root.numDisplayDevices; i++) {
        tabIndex = i + TAB_DISPLAY;

                CreateDisplayTabDialog(&tabs[tabIndex], g_dxdiagcom_root.displayDevices[i]);

    }
    for (i = 0; i < g_dxdiagcom_root.numSoundDevices; i++) {
        tabIndex =
            TAB_SOUND + (g_dxdiagcom_root.numDisplayDevices - 1) + i;
#ifdef TEST_MULTIPLE_SOUND
        create_sound_tab(&tabs[tabIndex],
                         g_dxdiagcom_root.soundDevices[0]);
#else
        create_sound_tab(&tabs[tabIndex],
                         g_dxdiagcom_root.soundDevices[i]);
#endif
    }

    create_input_tab(&tabs[tabIndex + 2]);
}

/* Procedure function for the Main Window */
LRESULT CALLBACK main_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam,
                               LPARAM lParam)
{
    switch (msg) {
    case WM_CREATE:
        /* Create */
        create_dialogs(hwnd);

        /* Show */
        set_default_window_size(hwnd);
        ShowWindow(g_hmaindialog, SW_SHOW);
        g_tabcontrol.displayArea = get_tabcontrol_displayarea();
        tab_control_display(&g_tabcontrol, TAB_SYSTEM);
        break;
    case WM_SIZE:
        resize_main_dialog(g_hmaindialog, LOWORD(lParam), HIWORD(lParam));
        g_tabcontrol.displayArea = get_tabcontrol_displayarea();
        tab_control_display(&g_tabcontrol, -1);
        break;
    case WM_CLOSE:
        DestroyWindow(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
    default:
        return DefWindowProcW(hwnd, msg, wParam, lParam);
    }
    return 0;
}
